use log::{debug, info};

#[derive(Debug, PartialEq)]
pub enum Command {
    None,
    CreateTopic, //创建 Topic
    List,
    Describe,
    Alter,
    GetOffset,
    DeleteTopic,
    Produce,
    Consume,
    DeleteGroup,
    Pull,
}

#[derive(Debug, PartialEq)]
pub enum ArgumentName {
    None,
    Topic,
    Partitions,
    FromBeginning,
    Offset,
    Group,
    ReplicationFactor,
    Len,
}

#[derive(Debug, PartialEq)]
pub enum Argument {
    None,
    End,
    Topic { topic: String },
    Partitions { partitions: u16 },
    FromBeginning { from_beginning: u16 },
    Offset { offset: usize },
    Group { group: String },
    ReplicationFactor { replication_factor: u16 },
    Len { len: usize },
}

#[derive(Debug)]
pub struct Token {
    pub command: Command,
    pub args: Vec<Argument>,
}

#[derive(Debug)]
pub struct Input<'a> {
    pub buf: &'a [u8],
    pub len: usize,
    pub current: usize,
}

impl<'a> Input<'a> {
    pub fn new(buf: &'a [u8], len: usize) -> Self {
        Input {
            buf,
            len,
            current: 0,
        }
    }

    pub fn analysis(&mut self) -> Option<Token> {
        let command = self.parse_command();
        //info!("socket_state:{:?}", command);
        if command == Command::None {
            return None;
        }

        let args = self.argument();
        //info!("{:?}", args);

        for arg in args.iter() {
            if *arg == Argument::None {
                return None;
            }
        }

        // for arg in args.iter() {
        //    println!("argument:{:?}", arg);
        // }

        Some(Token {
            command: command,
            args,
        })
    }

    pub fn argument(&mut self) -> Vec<Argument> {
        let mut args: Vec<Argument> = Vec::new();

        loop {
            if self.current >= (self.len - 1) || 
                (self.buf[self.current] as char).eq(&'\n') || 
                (self.buf[self.current + 1] as char).eq(&'\n') {
                args.push(Argument::End);
                return args;
            }

            if !Self::is_whitespace(self.buf[self.current] as char) {
                args.push(Argument::None);
                return args;
            }
            self.current += 1;

            let arg_type = self.argument_key();
            if arg_type == ArgumentName::None {
                args.push(Argument::None);
                return args;
            }

            if !Self::is_whitespace(self.buf[self.current] as char) {
                args.push(Argument::None);
                return args;
            }
            self.current += 1;

            let value = self.argument_value();

            let arg = match arg_type {
                ArgumentName::Topic => Argument::Topic { topic: value },
                ArgumentName::Partitions => Argument::Partitions {
                    partitions: value.parse().unwrap(),
                },
                ArgumentName::FromBeginning => Argument::FromBeginning {
                    from_beginning: value.parse().unwrap(),
                },
                ArgumentName::Group => Argument::Group { group: value },
                ArgumentName::Offset => Argument::Offset {
                    offset: value.parse().unwrap(),
                },
                ArgumentName::ReplicationFactor => Argument::ReplicationFactor {
                    replication_factor: value.parse().unwrap(),
                },
                ArgumentName::Len => Argument::Len {
                    len: value.parse().unwrap(),
                },
                _ => Argument::None,
            };

            args.push(arg);
        }
    }

    pub fn argument_value(&mut self) -> String {
        let mut value: String = String::new();
        while !Self::is_whitespace(self.buf[self.current] as char) {
            value.push(self.buf[self.current] as char);
            self.current += 1;
            if self.current >= self.len {
                break;
            }
        }
        value
    }

    pub fn argument_key(&mut self) -> ArgumentName {
        if Self::is_cross(self.buf[self.current]) && Self::is_cross(self.buf[self.current + 1]) {
            self.current += 2;

            let mut argument = String::new();
            while !Self::is_whitespace(self.buf[self.current] as char) {
                argument.push(self.buf[self.current] as char);
                self.current += 1;
                if self.current > self.len {
                    break;
                }
            }

            return match argument.as_str() {
                "topic" => ArgumentName::Topic,
                "partitions" => ArgumentName::Partitions,
                "replication-factor" => ArgumentName::ReplicationFactor,
                "from-beginning" => ArgumentName::FromBeginning,
                "offset" => ArgumentName::Offset,
                "group" => ArgumentName::Group,
                "len" => ArgumentName::Len,
                _ => ArgumentName::None,
            };
        }

        ArgumentName::None
    }

    pub fn is_whitespace(c: char) -> bool {
        c.is_whitespace()
    }

    pub fn is_cross(b: u8) -> bool {
        (b as char).eq(&'-')
    }

    // pub fn is_alphabetic(c: char) -> bool {
    //     c.is_alphabetic()
    // }

    pub fn parse_command(&mut self) -> Command {
        let mut command = String::new();
        while self.len != 0
            && self.len >= self.current
            && !Self::is_whitespace(self.buf[self.current] as char)
        {
            command.push(self.buf[self.current] as char);
            self.current += 1;
        }

        match command.as_str() {
            "create_topic" => Command::CreateTopic,
            "list" => Command::List,
            "describe" => Command::Describe,
            "alter" => Command::Alter,
            "get_offset" => Command::GetOffset,
            "delete_topic" => Command::DeleteTopic,
            "produce" => Command::Produce,
            "consume" => Command::Consume,
            "delete_group" => Command::DeleteGroup,
            "pull" => Command::Pull,
            _ => Command::None,
        }
    }
}
